// $Id: ptr_array.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_PTR_ARRAY_HPP
#define XPCOM_PTR_ARRAY_HPP

#include <xpcom/config.hpp>
#include <algorithm>
#include <xpcom/array_fwd.hpp>
#include <xpcom/array.hpp>
#include <xpcom/ptr.hpp>
#include <xpcom/detail/move.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {

//
// Array traits for XPCOM interface pointers.
//
template <typename T>
class ptr_array_traits : public proxy_array_traits<T*, ref_ptr<T> >
{
public:
    typedef construct_policy::zero_construct_tag construct_policy_tag;
};

//
// Array that contains XPCOM interface pointers.
//
template <typename T, typename Traits>
class ptr_array : public array_base<Traits>
{
    typedef ptr_array<T, Traits> this_type;
    typedef array_base<Traits> base_type;
    typedef typename base_type::impl_type impl_type;
public:
    typedef typename base_type::traits_type             traits_type;
    typedef typename base_type::element_type            element_type;
    typedef typename base_type::value_type              value_type;

    typedef typename base_type::size_type               size_type;
    typedef typename base_type::difference_type         difference_type;
    typedef typename base_type::pointer                 pointer;
    typedef typename base_type::const_pointer           const_pointer;
    typedef typename base_type::reference               reference;
    typedef typename base_type::const_reference         const_reference;

    typedef typename base_type::iterator                iterator;
    typedef typename base_type::const_iterator          const_iterator;
    typedef typename base_type::reverse_iterator        reverse_iterator;
    typedef typename base_type::const_reverse_iterator  const_reverse_iterator;

    ptr_array() :
        base_type()
    {
    }

    ptr_array(const ptr_array& rhs) :
        base_type(rhs)
    {
    }

    ptr_array(move_from<this_type> rhs) :
        base_type(move_from<base_type>(rhs.source))
    {
    }

    explicit ptr_array(size_type n) :
        base_type(n)
    {
    }

    template <typename ForwardIterator>
    ptr_array(ForwardIterator first, ForwardIterator last) :
        base_type(first, last)
    {
    }

    ~ptr_array()
    {
    }

    ptr_array& operator=(ptr_array rhs)
    {
        swap(rhs);
        return *this;
    }

    ptr_array& assign(const ptr_array& rhs)
    {
        this_type(rhs).swap(*this);
        return *this;
    }

    template <typename ForwardIterator>
    ptr_array& assign(ForwardIterator first, ForwardIterator last)
    {
        this_type(first, last).swap(*this);
        return *this;
    }

    void swap(ptr_array& rhs)
    {
        base_type::swap(rhs);
    }

protected:
    using base_type::impl_;

private:
    friend struct detail::array_access<this_type>;
};

// Comparisons
template <typename T, typename Traits>
bool operator==(
        const ptr_array<T, Traits>& lhs, const ptr_array<T, Traits>& rhs)
{
    return lhs.size() == rhs.size() &&
            std::equal(lhs.begin(), lhs.end(), rhs.begin());
}

template <typename T, typename Traits>
bool operator<(
        const ptr_array<T, Traits>& lhs, const ptr_array<T, Traits>& rhs)
{
    return std::lexicographical_compare(
            lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

template <typename T, typename Traits>
bool operator!=(
        const ptr_array<T, Traits>& lhs, const ptr_array<T, Traits>& rhs)
{
    return !(lhs == rhs);
}

template <typename T, typename Traits>
bool operator>(
        const ptr_array<T, Traits>& lhs, const ptr_array<T, Traits>& rhs)
{
    return rhs < lhs;
}

template <typename T, typename Traits>
bool operator<=(
        const ptr_array<T, Traits>& lhs, const ptr_array<T, Traits>& rhs)
{
    return !(rhs < lhs);
}

template <typename T, typename Traits>
bool operator>=(
        const ptr_array<T, Traits>& lhs, const ptr_array<T, Traits>& rhs)
{
    return !(lhs < rhs);
}

// swap
template <typename T, typename Traits>
inline void swap(ptr_array<T, Traits>& lhs, ptr_array<T, Traits>& rhs)
{
    lhs.swap(rhs);
}

} // namespace xpcom

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_PTR_ARRAY_HPP
